package services;

import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import manager.Start;
import model.Part;

public class PartService {
	
	//-------------------------------------------------------------
	public static boolean isPointInPart(int x, int y, final Part part) {
		List<Integer> polyX = new ArrayList<Integer>();
		for (int tmpX : part.getPolyX()) {
			polyX.add(tmpX);
		}
		
		List<Integer> polyY = new ArrayList<Integer>();
		for (int tmpY : part.getPolyY()) {
			polyY.add(tmpY);
		}
		
		int polySides = polyY.size();
		int i,j = polySides -1;
		boolean oddNodes = false;
		
		for (i = 0; i < polySides; i++) {
			if ((polyY.get(i) < y && polyY.get(j) >= y) ||
				(polyY.get(j) < y && polyY.get(i) >= y)) {
				if (polyX.get(i) + (y - polyY.get(i))/(polyY.get(j) - polyY.get(i)) * (polyX.get(j) - polyX.get(i)) <= x) {
					oddNodes = !oddNodes;
				}
				j=i;
			}
		}
		
		return oddNodes;
	}
	
	
	//---------------------------------------------
	public static Part getContainingPart(int x, int y) {
		List<Part> allPartList = getBoardParts();
		
		for (final Part tmpPart : allPartList) {
			if (PartService.isPointInPart(x,y, tmpPart)) {
				return tmpPart;
			}
		}
		
		return null;
	}
	
	public static List<Part> getBoardParts() {
		List<Part> allPartList = Start.getGame().getBoard().getAllPartList();
		
		for (final Part tmpPart : allPartList) {
			System.out.println(tmpPart.getRow() + "" +
					"(" + tmpPart.getColumn() + 
					"," + tmpPart.getPolyX()[0] +
					"," + tmpPart.getPolyX()[1] + 
					"," + tmpPart.getPolyX()[2] + 
					"," + tmpPart.getPolyX()[3] + 
					"," + tmpPart.getPolyX()[4] +
					"," + tmpPart.getPolyX()[5] +
					")(" +
					"," + tmpPart.getPolyY()[0] +
					"," + tmpPart.getPolyY()[1] +
					"," + tmpPart.getPolyY()[2] +
					"," + tmpPart.getPolyY()[3] +
					"," + tmpPart.getPolyY()[4] +
					"," + tmpPart.getPolyY()[5] +
					")");
		
		}
		
		return allPartList;
	}
	
	//-----------------------------------------------------
	public static List<Part> getNotChosenBoardParts() {
		List<Part> notChosenPartList = new LinkedList<Part>();
		
		for (Part tmpPart : PartService.getBoardParts()) {
			if (tmpPart.getColor() == Color.CYAN) {
				notChosenPartList.add(tmpPart);
			}
		}
		
		return notChosenPartList;
	}
	
	//---------------------------------------
	public static boolean isAllBoardPartsChosen() {
		for (final Part tmpPart : PartService.getBoardParts()) {
			if (tmpPart.getColor() == Color.CYAN) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * Given a part, the method returns all the neighbors of this part
	 * @param part
	 * @return
	 */
	public static List<Part> getNeighbors(Part part) {
		List<Part> neighborsList = new LinkedList<Part>();
		int boardSize = Start.getGame().getBoard().getBoardSize();
		int x = part.getRow();
		int y = part.getColumn();
		
		if ((x-1)>=0) {
			if ((y-1) >= 0) 
				neighborsList.add(Start.getGame().getBoard().getParts()[x-1][y-1]);
			if ((y+1) < boardSize)
				neighborsList.add(Start.getGame().getBoard().getParts()[x-1][y+1]);
			if ((x-2)>=0)
				neighborsList.add(Start.getGame().getBoard().getParts()[x-2][y]);
		}
		if ((x+1) < boardSize) {
			if ((y-1)>=0) 
				neighborsList.add(Start.getGame().getBoard().getParts()[x+1][y-1]);
			if ((y+1) < boardSize)
				neighborsList.add(Start.getGame().getBoard().getParts()[x+1][y+1]);
			if ((x+2) < boardSize)
				neighborsList.add(Start.getGame().getBoard().getParts()[x+2][y]);
		}
		
		return neighborsList;
	}
	
	/**
	 * Given a part, the method returns all the chosen neighbors of this part
	 * @param part
	 * @return
	 */
	public static List<Part> getChosenNeighbors(Part part) {
		List<Part> chosenNeighborsList = new LinkedList<Part>();
		
		for (Part tmpPart : PartService.getNeighbors(part)) {
			if (tmpPart.getColor() != Color.CYAN) {
				chosenNeighborsList.add(tmpPart);
			}
		}
		
		return chosenNeighborsList;
	}
	
	/**
	 * Given a part, the method returns all the not chosen neighbors of this part
	 * @param part
	 * @return
	 */
	public static List<Part> getNotChosenNeighbors(Part part) {
		List<Part> notChosenNeighborsList = new LinkedList<Part>();
		
		for (Part tmpPart : PartService.getNeighbors(part)) {
			if (tmpPart.getColor() == Color.CYAN) {
				notChosenNeighborsList.add(tmpPart);
			}
		}
		
		return notChosenNeighborsList;
	}
	
	/**
	 * Given a part, this method returns all the chosen neighbors of this part
	 * that their color is the given color
	 * @param part
	 * @return
	 */
	public static List<Part> getSpecificColorNeighbors(Part part, Color color) {
		List<Part> coloredNeighborsList = new LinkedList<Part>();
		
		for (Part tmpPart : PartService.getNeighbors(part)) {
			if (tmpPart.getColor() == color) {
				coloredNeighborsList.add(tmpPart);
			}
		}
		
		return coloredNeighborsList;
	}
	
	/**
	 * The method will return true if the part given is surrounded
	 * only with the chosen neighbors
	 * @param part
	 * @return
	 */
	public static boolean isSurrounded(Part part) {
		int neighbors = PartService.getNeighbors(part).size();
		int chosenNeighbors = PartService.getChosenNeighbors(part).size();
		
		return (neighbors == chosenNeighbors);
	}
	
	/**
	 * In order to know if choosing this part will cause winning,
	 * we need to know if it has caused one of the opponent's neighbors 
	 * to be surrounded
	 * @param part
	 * @return
	 */
	public static boolean isOneOfOpponentNeighborsSurrounded(Part part) {
		Color opponentTurn = StepService.getOpponentTurn(part.getColor());
		
		for (Part opponentPart : getSpecificColorNeighbors(part, opponentTurn)) {
			if (PartService.isSurrounded(opponentPart)) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * If choosing this part will surround of its neighbors that
	 * has the same color, then it will prevent the opponent winning
	 * by surrounding this neighbor 
	 * @param part
	 * @return
	 */
	public static boolean isOneOfPartColorNeighborsSurrounded(Part part) {
		for (Part partColorNeighbor : PartService.getSpecificColorNeighbors(part, part.getColor())) {
			if (PartService.isSurrounded(partColorNeighbor)) {
				return true;
			}
		}
		
		return false;
	}

}
